package cn.csc.framework.pay.core.client.impl.jh;

import cn.csc.framework.pay.core.client.AbstractPayCodeMapping;
import cn.csc.framework.pay.core.client.PayCommonResult;
import cn.csc.framework.pay.core.client.dto.*;
import cn.csc.framework.pay.core.client.impl.AbstractPayClient;
import cn.csc.framework.pay.core.client.impl.jh.util.JHPayService;
import cn.csc.framework.pay.core.enums.PayNotifyRefundStatusEnum;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.http.HttpUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import lombok.extern.slf4j.Slf4j;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static cn.csc.framework.common.util.json.JsonUtils.toJsonString;
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
import static cn.hutool.core.date.DatePattern.PURE_DATETIME_FORMATTER;

@Slf4j
public abstract class AbstractJHClient extends AbstractPayClient<JHPayClientConfig> {

    /**
     * 网关地址 - 线上
     */
    public static final String SERVER_URL_PROD = "https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6";
    /**
     * 网关地址 - 测试
     */
    public static final String SERVER_URL_TEST = "https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6";


    protected JHPayService jHPayService;

    public AbstractJHClient(BigInteger channelId, String channelCode, JHPayClientConfig config, AbstractPayCodeMapping codeMapping) {
        super(channelId, channelCode, config,codeMapping);
    }

    @Override
    protected void doInit() {
        config.setGateway(Optional.ofNullable(config.getGateway()).orElse("0"));
        config.setUrl(Optional.ofNullable(config.getUrl()).orElse(SERVER_URL_PROD));
        config.setCurCode(Optional.ofNullable(config.getCurCode()).orElse("01"));
        jHPayService = new JHPayService(config);
    }

    /**
     * 从支付宝通知返回参数中解析 PayOrderNotifyRespDTO, 通知具体参数参考
     *  //https://opendocs.alipay.com/open/203/105286
     * @param data 通知结果
     * @return 解析结果 PayOrderNotifyRespDTO
     * @throws Exception  解析失败，抛出异常
     */
    @Override
    public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception {
        Map<String, String> params = data.getParams();
        Map<String, String> bodyObj = HttpUtil.decodeParamMap(data.getBody(), StandardCharsets.UTF_8);
        PayOrderNotifyRespDTO r =new PayOrderNotifyRespDTO();
        return r;
//        return  PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("cusorderid"))
//                .channelOrderNo(bodyObj.get("trxid"))
//                .tradeStatus("trxstatus").successTime(parseMuchTime(params.get("paytime")))
//                .build();
    }

    @Override
    public PayRefundNotifyRespDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
        Map<String, String> params = strToMap(notifyData.getBody());
        PayRefundNotifyRespDTO notifyDTO = PayRefundNotifyRespDTO.builder().channelOrderNo(params.get("trade_no"))
                .tradeNo(params.get("out_trade_no"))
                .reqNo(params.get("out_biz_no"))
                .status(PayNotifyRefundStatusEnum.SUCCESS)
                .refundSuccessTime(LocalDateTimeUtil.parse(params.get("gmt_refund"), "yyyy-MM-dd HH:mm:ss"))
                .rawData(notifyData.getBody())
                .build();
        return notifyDTO;
    }

    @Override
    public boolean isRefundNotify(PayNotifyDataDTO notifyData) {
        if (notifyData.getParams().containsKey("refund_fee")) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean verifyNotifyData(PayNotifyDataDTO notifyData) {
        boolean verifyResult = false;
        try {
            verifyResult =  AlipaySignature.rsaCheckV1(notifyData.getParams(), config.getPub(), StandardCharsets.UTF_8.name(), "RSA2");
        } catch (AlipayApiException e) {
            log.error("[AlipayClient verifyNotifyData][(notify param is :{}) 验证失败]", toJsonString(notifyData.getParams()), e);
        }
        return verifyResult;
    }

    @Override
    protected PayCommonResult<PayRefundUnifiedRespDTO> doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO)  {
        return null;
    }



    /**
     * 支付宝统一回调参数  str 转 map
     *
     * @param s 支付宝支付通知回调参数
     * @return map 支付宝集合
     */
    public static Map<String, String> strToMap(String s) {
        // TODO @zxy：这个可以使用 hutool 的 HttpUtil decodeParams 方法么？
        Map<String, String> stringStringMap = new HashMap<>();
        // 调整时间格式
        String s3 = s.replaceAll("%3A", ":");
        // 获取 map
        String s4 = s3.replace("+", " ");
        String[] split = s4.split("&");
        for (String s1 : split) {
            String[] split1 = s1.split("=");
            stringStringMap.put(split1[0], split1[1]);
        }
        return stringStringMap;
    }

    /**
     * 支付宝统一的退款接口 alipay.trade.refund
     * @param reqDTO 退款请求 request DTO
     * @return 退款请求 Response
     */
    @Override
    protected PayRefundUnifiedRespDTO doUnifiedBeanRefund(PayRefundUnifiedReqDTO reqDTO)  {
        return null;
    }

    @Override
    protected abstract PayOrderUnifiedRespDTO doUnifiedBeanOrder(PayOrderUnifiedReqDTO reqDTO) throws Throwable;

    /**
     * 获得支付订单信息
     *
     * @param outTradeNo 外部订单号
     * @return 支付订单信息
     */
    @Override
    protected PayOrderUnifiedRespDTO doGetOrder(String outTradeNo) throws Throwable{
        // TODO 实现订单查询
        return null;
    }



    @Override
    public Object parseNotify(PayNotifyReqDTO rawNotify) {
        // 1. 校验回调数据
        String body = rawNotify.getBody();
        Map<String, String> params = rawNotify.getParams();
        Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);

        // 2.1 退款的情况
        if (bodyObj.containsKey("refund_fee")) {
            return PayRefundNotifyRespDTO.builder().channelOrderNo(bodyObj.get("trade_no"))
                    .tradeNo(bodyObj.get("out_trade_no")).reqNo(bodyObj.get("out_biz_no"))
                    .status(PayNotifyRefundStatusEnum.SUCCESS)
                    .refundSuccessTime(parseTime(params.get("gmt_refund")))
                    .build();
        }
        // 2.2 支付的情况
        return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("cusorderid"))
                .channelOrderNo(bodyObj.get("trxid"))
                .tradeStatus("trxstatus").successTime(parseMuchTime(params.get("paytime")))
                .build();

    }


    protected LocalDateTime parseMuchTime(String str) {
        LocalDateTime t1 = LocalDateTimeUtil.parse(str, PURE_DATETIME_FORMATTER);
        String t2 = LocalDateTimeUtil.format(t1,NORM_DATETIME_FORMATTER);
        return LocalDateTimeUtil.parse(t2, NORM_DATETIME_FORMATTER);
    }
}
